package com.hrvsr.downloader.httpclient;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;

import org.apache.http.HttpHost;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;

import com.hrvsr.common.util.StrUtil;




public class ClientFactory {
	private static final int TIME_OUT = 30 * 1000;
	private static final String PROXY = null;
	private static final String COOKIE_SEPC = CookieSpecs.NETSCAPE;
	private static final int RETRY_TIMES = 3;

	public static CloseableHttpClient getNewClient() {
		return getNewClient(TIME_OUT, RETRY_TIMES, PROXY, COOKIE_SEPC);
	}

	public static CloseableHttpClient getNewClient(String proxy) {
		return getNewClient(TIME_OUT, RETRY_TIMES, proxy, COOKIE_SEPC);
	}

	public static CloseableHttpClient getNewClient(HttpHost proxy) {
		String h = proxy.getHostName();
		int port = proxy.getPort();
		return getNewClient(TIME_OUT, RETRY_TIMES, h + ":" + port, COOKIE_SEPC);
	}
	
	public static CloseableHttpClient getNewClient(int timeOut, int retryTimes){
		return getNewClient(timeOut, retryTimes, null, COOKIE_SEPC);
	}

	public static CloseableHttpClient getNewClient(int timeOut, final int retryTimes, String proxy, String cookieSpec) {
		try {
			SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, new TrustStrategy() {
				@Override
				public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
					return true;
				}

			}).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
					new HostnameVerifier() {
				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					return true;
				}
			});
			
			Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();

			PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(reg);

			HttpHost host = getProxy(proxy);

			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(timeOut)
					.setConnectTimeout(timeOut)
					.setConnectionRequestTimeout(timeOut)
					.setCookieSpec(cookieSpec)
					.setProxy(host)
					.setRedirectsEnabled(true)
					.setMaxRedirects(10)
					.build();

			CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(connMgr)
					.setRedirectStrategy(new LaxRedirectStrategy())
					.setRetryHandler(new HttpRequestRetryHandler() {
						@Override
						public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
							if (executionCount < retryTimes) {
								return true;
							}
							return false;
						}
					}).build();
			return client;

		} catch (Exception e) {
			return null;
		}
	}
	
	public static CloseableHttpClient getNewClient(int timeOut, final int retryTimes, int thread, String proxy, String cookieSpec) {
		try {
			SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial(null, new TrustStrategy() {
				@Override
				public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
					return true;
				}

			}).build();

			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
					new HostnameVerifier() {
				@Override
				public boolean verify(String arg0, SSLSession arg1) {
					return true;
				}
			});
			
			Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();

			PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(reg);
			connMgr.setDefaultMaxPerRoute(thread);
			connMgr.setMaxTotal(thread);
			
			
			HttpHost host = getProxy(proxy);

			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(timeOut)
					.setConnectTimeout(timeOut)
					.setConnectionRequestTimeout(timeOut)
					.setCookieSpec(cookieSpec)
					.setProxy(host)
					.setRedirectsEnabled(true)
					.setMaxRedirects(10)
					.build();

			CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig)
					.setConnectionManager(connMgr)
					.setRedirectStrategy(new LaxRedirectStrategy())
					.setRetryHandler(new HttpRequestRetryHandler() {
						@Override
						public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
							if (executionCount < retryTimes) {
								return true;
							}
							return false;
						}
					}).build();
			return client;

		} catch (Exception e) {
			return null;
		}

	}
	
	public static CloseableHttpClient getNewClient(int timeOut, final int retryTimes, int threadNum) {
		return getNewClient(timeOut, retryTimes, threadNum, null, COOKIE_SEPC);
	}

	private static HttpHost getProxy(String proxy) {
		if (StrUtil.isEmpty(proxy)) {
			return null;
		}
		String[] ss = proxy.split(":");
		String host = ss[0];
		int port = 80;
		if (ss.length > 0) {
			port = Integer.parseInt(ss[1]);
		}
		return new HttpHost(host, port);
	}

}
